Nonterminals pass call args exprs lor land cond expr.

Terminals 'boolean' 'integer' 'string' 'name' 
		  '.' '[' ']' '(' ')' ',' ':'
		  '==' '!=' '<' '<=' '>' '>=' '&&' '||' '!'.


Rootsymbol lor.

exprs -> lor :				['$1'].
exprs -> lor ',' exprs : 	['$1'|'$3'].

lor  -> land :  			'$1'.
lor  -> land '||' lor :		lor('$1', '$3').
land -> cond :  			'$1'.
land -> cond '&&' land :	land('$1', '$3').

cond -> expr :	  	   		'$1'.
cond -> expr '==' cond :	equal('$1', '$3').
cond -> expr '!=' cond :	not_equal('$1', '$3').
cond -> expr '<'  cond :	lt('$1', '$3').
cond -> expr '<=' cond :	lt_eq('$1', '$3').
cond -> expr '>'  cond :	gt('$1', '$3').
cond -> expr '>=' cond :	gt_eq('$1', '$3').

expr -> boolean : 		  	value_of('$1').
expr -> integer : 		  	value_of('$1').
expr -> string :			value_of('$1').
expr -> pass :				'$1'.
expr -> call :				'$1'.
expr -> '!' expr :			negate('$2').
expr -> '(' lor ')' : 		('$2').

pass -> name :				templel_context:get_by_key('$1').
pass -> pass '.' name : 	templel_context:get_by_key('$1', '$3').
%pass -> pass '[' expr ']' : templel_context:get_by_index('$1', '$3').
pass -> pass '[' expr ']' : lists:nth('$3', '$1').

call -> name ':' name args : apply(list_to_atom(value_of('$1')), list_to_atom(value_of('$3')), '$4').
call -> pass ':' pass args : apply('$1', '$3', '$4').
% duplicated
call -> pass pass args :  	apply('$1', '$2', '$3').

args -> '(' ')' : 		   	none.
args -> '(' exprs ')' :		'$2'.


Erlang code.
%to_string(Expr) when is_atom(Expr) ->
%	atom_to_list(Expr);
%to_string(Expr) when is_integer(Expr) ->
%	integer_to_list(Expr);
%to_string(Expr) ->
%	Expr.

value_of(Token) ->
	element(3, Token).
%line_of(Token) ->
%	element(2, Token).

negate(B) when is_boolean(B) ->
	not(B);
negate(Expr) ->
	erlang:error({badarg, [Expr]}).

equal(true, true) -> true;
equal(false, false) -> true;
%
equal(I1, I2)
  when is_integer(I1), is_integer(I2) ->
  	if
		I1 =:= I2 -> true;
		true -> false
	end;
%
equal([C1|Cs1], [C2|Cs2]) when C1 =:= C2 ->
    equal(Cs1, Cs2);
equal([], []) -> true;
%
equal(_Expr1, _Expr2) -> false.

not_equal(Expr1, Expr2) ->
	not( equal(Expr1, Expr2) ).

lt(I1, I2)
  when is_integer(I1), is_integer(I2) ->
	I1 < I2;
lt(Expr1, Expr2) ->
	erlang:error({badarg, [Expr1,Expr2]}).

lt_eq(I1, I2)
  when is_integer(I1), is_integer(I2) ->
	I1 =< I2;
lt_eq(Expr1, Expr2) ->
	erlang:error({badarg, [Expr1,Expr2]}).

gt(I1, I2)
  when is_integer(I1), is_integer(I2) ->
	I1 > I2;
gt(Expr1, Expr2) ->
	erlang:error({badarg, [Expr1,Expr2]}).

gt_eq(I1, I2)
  when is_integer(I1), is_integer(I2) ->
	I1 >= I2;
gt_eq(Expr1, Expr2) ->
	erlang:error({badarg, [Expr1,Expr2]}).

land(B1, B2)
  when is_boolean(B1), is_boolean(B2) ->
  	if
		B1, B2 -> true;
		true -> false
	end;
land(Expr1, Expr2) ->
	erlang:error({badarg, [Expr1,Expr2]}).

lor(B1, B2)
  when is_boolean(B1), is_boolean(B2) ->
  	if
		B1; B2 -> true;
		true -> false
	end;
lor(Expr1, Expr2) ->
	erlang:error({badarg, [Expr1,Expr2]}).
